package com.bcx.wind.workflow.imp.cmd.repositorycmd.windprocesscmd;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.ProcessStatus;
import com.bcx.wind.workflow.core.flow.node.ProcessModel;
import com.bcx.wind.workflow.entity.WindProcess;
import com.bcx.wind.workflow.entity.WindProcessModule;
import com.bcx.wind.workflow.errorcontext.WindError;
import com.bcx.wind.workflow.interceptor.Command;
import com.bcx.wind.workflow.interceptor.CommandContext;
import com.bcx.wind.workflow.parser.ProcessBuilder;
import com.bcx.wind.workflow.parser.ProcessBuilderFactory;
import com.bcx.wind.workflow.support.Assert;
import com.bcx.wind.workflow.support.ObjectHelper;
import com.bcx.wind.workflow.support.StreamHelper;
import com.bcx.wind.workflow.support.TimeHelper;

import java.io.InputStream;
import java.util.Comparator;
import java.util.List;

import static com.bcx.wind.workflow.core.constant.Constant.ROOT_MODULE;
import static com.bcx.wind.workflow.message.ErrorCode.DATABASE_OPERATE_ERROR;
import static com.bcx.wind.workflow.message.ErrorCode.PROCESS_MODULE_NOT_FOUND;

/**
 * 添加流程定义命令实现
 *
 * @author zhanglei
 */
public class AddProcessCommand implements Command<WindProcess> {

    /**
     * 流程定义xml数据
     */
    private String xml;

    /**
     * 系统标识
     */
    private String system;


    /**
     * 流程定义所属模块
     */
    private String module;


    /**
     * 流程定义流数据
     */
    private InputStream stream;

    /**
     * 流程模型对象
     */
    private ProcessModel processModel;

    /**
     * 命令数据
     */
    private CommandContext context;

    /**
     * 版本
     */
    private int version = 1;

    /**
     * 父ID
     */
    private  String parentId;

    /**
     * 流程定义二进制
     */
    private  byte[] bytes;

    public AddProcessCommand(String xml,String system){
        this.xml = xml;
        this.system = system;
    }

    public AddProcessCommand(InputStream stream,String system){
        this.stream = stream;
        this.system = system;
    }

    public AddProcessCommand(String xml,String system,String module){
        this.xml = xml;
        this.system = system;
        this.module = module;
    }

    public AddProcessCommand(InputStream stream,String system,String module){
        this.stream = stream;
        this.system = system;
        this.module = module;
    }

    @Override
    public WindProcess executor(CommandContext context) {
        try{
            this.context = context;
            return execute();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 执行
     *
     * @return  流程定义
     */
    private  WindProcess  execute(){
        //校验参数
        checkVariable();
        //校验构建流程定义对象
        buildProcessModel();
        //旧流程
        oldProcess();
        //创建新流程定义
        return buildProcess();
    }


    private void checkVariable() {
        if(this.module != null){
            WindProcessModule windProcessModule = this.context.access().selectProcessModuleById(this.module);
            Assert.notEmptyError(PROCESS_MODULE_NOT_FOUND,windProcessModule);
            return;
        }

        //如果为空，则使用默认根模块
        this.module = ROOT_MODULE;
    }


    /**
     * 构建流程定义对象
     *
     * @return  流程定义实体对象
     */
    private  WindProcess buildProcess(){
        WindProcess process =  new WindProcess()
                   .setId(this.processModel.getProcessId())
                   .setProcessName(this.processModel.getProcessName())
                   .setDisplayName(this.processModel.getProcessDisplayName())
                   .setStatus(ProcessStatus.TEMPLATE)
                   .setVersion(this.version)
                   .setParentId(this.parentId)
                   .setCreateTime(TimeHelper.nowDate())
                   .setContent(this.bytes)
                   .setSystem(system)
                   .setModule(this.module);
        int ret = this.context.access().addProcess(process);
        if(ret != 1){
            WindError.error(DATABASE_OPERATE_ERROR,null);
        }
        return process;
    }

    /**
     * 查询有没有旧版本的流程定义数据 设置版本 父流程定义ID
     */
    private void  oldProcess(){
        if(processModel != null) {
            String processName = this.processModel.getProcessName();
            QueryFilter filter = new QueryFilter()
                    .setProcessName(processName);

            List<WindProcess> processes = this.context.access().selectProcessList(filter);
            if (!ObjectHelper.isEmpty(processes)) {
                WindProcess maxVersionProcess = processes.stream().max(Comparator.comparingInt(WindProcess::getVersion))
                        .orElseThrow(()->WindError.error("process version not found error ! "));
                this.version = maxVersionProcess.getVersion() + 1;
                this.parentId = maxVersionProcess.getId();
            }
        }
    }


    private  void  buildProcessModel(){
        ProcessBuilder builder = ProcessBuilderFactory.getBuilder(processContent());
        builder.buildProcess(ObjectHelper.primaryKey());
        this.processModel = builder.getProcessModel();
    }


    private  String  processContent(){
        if(this.xml != null){
            this.bytes = xml.getBytes();
            return xml;
        }else if(this.stream != null){
            String content = StreamHelper.getStr(stream);
            this.bytes = content.getBytes();
            return content;
        }
        return null;
    }


}
